﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;

using PlanningGIS.ArcGIS;
using PlanningGIS.Util.Log;
using PlanningGIS.Engine.Controls;

namespace PlanningGIS.DataCheck.model
{
    /// <summary>
    /// 接边检查
    /// </summary>
    public class MergeCheck : Check
    {
        private List<IFeatureLayer> pFeatLyrs;
        private IPolyline pPolyline;

        private double buffer;
        private double minTol;
        private double maxTol;
        private bool needSyncretizeCheck;

        public List<IFeatureLayer> FeatLyrs
        {
            set { pFeatLyrs = value; }
        }

        public IPolyline Polyline
        {
            set { pPolyline = value; }
        }

        public double Buffer
        {
            set { buffer = value; }
        }

        public double MinTol
        {
            set { minTol = value; }
        }

        public double MaxTol
        {
            set { maxTol = value; }
        }

        public bool NeedSyncretizeCheck
        {
            set { needSyncretizeCheck = value; }
        }

        public int Check()
        {
            int errCount = 0;

            if (pFeatLyrs == null || pFeatLyrs.Count == 0) return 0;
            if (buffer < 0)
            {
               LogHelper.WriteErrLog("搜索缓冲必须为非负数！");
                return 0;
            }

            if (minTol < 0)
            {
               LogHelper.WriteErrLog("容限值下限必须为非负数！");
                return 0;
            }

            if (maxTol < 0)
            {
               LogHelper.WriteErrLog("容限值上限必须为非负数！");
                return 0;
            }

            //如果两个都为0，则表示仅查融合
            if (minTol >= maxTol && minTol !=0)
            {
               LogHelper.WriteErrLog("容限值上限不得小于容限值下限！");
                return 0;
            }

            if(pPolyline ==null || pPolyline.IsEmpty )
            {
               LogHelper.WriteErrLog ("请选择需要接边的边界线！");
                return 0;
            }

            IGeometry pGeometry = GeometryHelper.GetBuffer(pPolyline, buffer);

            setProcessBarMax.Invoke(pFeatLyrs.Count);

            int i = 0;

            foreach (IFeatureLayer pFeatLyr in pFeatLyrs)
            {
                setProcessBarCurrent.Invoke(++i);
                if (IsStop()) break;

                //if (!pGeometry.SpatialReference.Equals((pFeatLyr.FeatureClass as IGeoDataset).SpatialReference))
                //{
                    pGeometry.Project((pFeatLyr.FeatureClass as IGeoDataset).SpatialReference);
                //}

                switch (pFeatLyr.FeatureClass.ShapeType)
                {
                    case esriGeometryType.esriGeometryPolyline :
                        errCount = errCount + PolylineMergeCheck(pFeatLyr, pGeometry);
                        break;

                    case esriGeometryType.esriGeometryPolygon :
                        errCount = errCount + PolygonMergeCheck(pFeatLyr, pGeometry);
                        break;

                    default :
                       LogHelper.WriteErrLog("接边检查目前不支持[" + pFeatLyr.Name + "]数据的格式！");
                        break;
                }
            }

            //LogHelper.WriteDoneLog("接边检查完毕，共找出" + errCount + "处错误。\r\n");

            return errCount;
        }

        /// <summary>
        /// 判断两个要素是否属性相同,相同返回true,否则返回false,若两个要素为同一个要素也返回false
        /// </summary>
        /// <param name="pfeat1"></param>
        /// <param name="pfeat2"></param>
        /// <param name="pArray"></param>
        /// <returns></returns>
        private bool IsSameAttr(IFeature pfeat1, IFeature pfeat2)
        {
            if ((pfeat1 == null) && (pfeat2 == null))
            {
                return false;
            }
            IField pFld;
            object obj1, obj2;
            try
            {
                for (int idx = 0; idx < pfeat1.Fields.FieldCount; idx++)
                {
                    pFld = pfeat1.Fields.get_Field(idx);
                    if (pFld.Editable == false) continue;
                    if (pfeat2.Fields.FindField(pFld.Name) < 0) continue;
                    switch (pFld.Type)
                    {
                        case esriFieldType.esriFieldTypeInteger:
                        case esriFieldType.esriFieldTypeSmallInteger:
                            {
                                obj1 = pfeat1.get_Value(idx);
                                obj2 = pfeat2.get_Value(idx);
                                long lngValue1 = 0, lngValue2 = 0;
                                if (obj1 != DBNull.Value)
                                {
                                    lngValue1 = Convert.ToInt64(obj1);
                                }
                                if (obj2 != DBNull.Value)
                                {
                                    lngValue2 = Convert.ToInt64(obj2);
                                }
                                if (lngValue1 != lngValue2) return false;
                                break;
                            }
                        case esriFieldType.esriFieldTypeSingle:
                        case esriFieldType.esriFieldTypeDouble:
                            {
                                obj1 = pfeat1.get_Value(idx);
                                obj2 = pfeat2.get_Value(idx);
                                double dblValue1 = 0, dblValue2 = 0;
                                if (obj1 != DBNull.Value)
                                {
                                    dblValue1 = Convert.ToDouble(obj1);
                                }
                                if (obj2 != DBNull.Value)
                                {
                                    dblValue2 = Convert.ToDouble(obj2);
                                }
                                if (Math.Abs(dblValue1 - dblValue2) > 0.001) return false;
                                break;
                            }
                        case esriFieldType.esriFieldTypeDate:
                            {
                                obj1 = pfeat1.get_Value(idx);
                                obj2 = pfeat2.get_Value(idx);
                                DateTime dtValue1 = DateTime.Now, dtValue2 = DateTime.Now;
                                if (obj1 != DBNull.Value)
                                {
                                    dtValue1 = Convert.ToDateTime(obj1);
                                }
                                if (obj2 != DBNull.Value)
                                {
                                    dtValue2 = Convert.ToDateTime(obj2);
                                }
                                if (dtValue1.Equals(dtValue2) == false) return false;
                                break;
                            }
                        case esriFieldType.esriFieldTypeString:
                            {
                                obj1 = pfeat1.get_Value(idx);
                                obj2 = pfeat2.get_Value(idx);
                                string str1 = "", str2 = "";
                                if (obj1 != DBNull.Value)
                                {
                                    str1 = obj1.ToString().Trim();
                                }
                                if (obj2 != DBNull.Value)
                                {
                                    str2 = obj2.ToString().Trim();
                                }
                                if (str1 == "0") str1 = "";
                                if (str2 == "0") str2 = "";
                                if (str1 != str2) return false;
                                break;
                            }
                        default:
                            {
                                break;
                            }
                    }

                }
                return true;
            }
            catch (Exception e)
            {
                return false;
            }
        }

        private List<string> GetNotSameValueFlds(IFeature pfeat1, IFeature pfeat2)
        {
            List<string> pFldsList = new List<string>();
            IField pFld;
            object obj1, obj2;
            try
            {
                for (int idx = 0; idx < pfeat1.Fields.FieldCount; idx++)
                {
                    pFld = pfeat1.Fields.get_Field(idx);
                    if (pFld.Editable == false) continue;
                    int idx2 = pfeat2.Fields.FindField(pFld.Name);
                    if (idx2 < 0) continue;
                    switch (pFld.Type)
                    {
                        case esriFieldType.esriFieldTypeInteger:
                        case esriFieldType.esriFieldTypeSmallInteger:
                            {
                                obj1 = pfeat1.get_Value(idx);
                                obj2 = pfeat2.get_Value(idx2);
                                long lngValue1 = 0, lngValue2 = 0;
                                if (obj1 != DBNull.Value)
                                {
                                    lngValue1 = Convert.ToInt64(obj1);
                                }
                                if (obj2 != DBNull.Value)
                                {
                                    lngValue2 = Convert.ToInt64(obj2);
                                }
                                if (lngValue1 != lngValue2)
                                {
                                    pFldsList.Add(pFld.AliasName);
                                }
                                break;
                            }
                        case esriFieldType.esriFieldTypeSingle:
                        case esriFieldType.esriFieldTypeDouble:
                            {
                                obj1 = pfeat1.get_Value(idx);
                                obj2 = pfeat2.get_Value(idx2);
                                double dblValue1 = 0, dblValue2 = 0;
                                if (obj1 != DBNull.Value)
                                {
                                    dblValue1 = Convert.ToDouble(obj1);
                                }
                                if (obj2 != DBNull.Value)
                                {
                                    dblValue2 = Convert.ToDouble(obj2);
                                }
                                if (Math.Abs(dblValue1 - dblValue2) > 0.001)
                                {
                                    pFldsList.Add(pFld.AliasName);
                                }
                                break;
                            }
                        case esriFieldType.esriFieldTypeDate:
                            {
                                obj1 = pfeat1.get_Value(idx);
                                obj2 = pfeat2.get_Value(idx2);
                                DateTime dtValue1 = DateTime.Now, dtValue2 = DateTime.Now;
                                if (obj1 != DBNull.Value)
                                {
                                    dtValue1 = Convert.ToDateTime(obj1);
                                }
                                if (obj2 != DBNull.Value)
                                {
                                    dtValue2 = Convert.ToDateTime(obj2);
                                }
                                if (dtValue1.Equals(dtValue2) == false)
                                {
                                    pFldsList.Add(pFld.AliasName);
                                }
                                break;
                            }
                        case esriFieldType.esriFieldTypeString:
                            {
                                obj1 = pfeat1.get_Value(idx);
                                obj2 = pfeat2.get_Value(idx2);
                                string str1 = "", str2 = "";
                                if (obj1 != DBNull.Value)
                                {
                                    str1 = obj1.ToString().Trim();
                                }
                                if (obj2 != DBNull.Value)
                                {
                                    str2 = obj2.ToString().Trim();
                                }
                                if (str1 == "0") str1 = "";
                                if (str2 == "0") str2 = "";
                                if (str1 != str2)
                                {
                                    pFldsList.Add(pFld.AliasName);
                                }
                                break;
                            }
                        default:
                            {
                                break;
                            }
                    }

                }

            }
            catch (Exception e)
            {

            }
            return pFldsList;
        }

        private List<int> GetNeedCheckIds(IFeatureClass pFeatCls, IGeometry pGeometry)
        {
            List<int> ids = new List<int>();

            ISpatialFilter pSpatialFilter = new SpatialFilterClass();
            pSpatialFilter.GeometryField = pFeatCls.ShapeFieldName;
            pSpatialFilter.Geometry = pGeometry;
            pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;

            IFeatureCursor pFeatCur = pFeatCls.Search(pSpatialFilter, false);
            IFeature pFeature;
            while ((pFeature = pFeatCur.NextFeature()) != null)
            {
                ids.Add(pFeature.OID);
            }

            pSpatialFilter = null;
            DataCheckUtility.ReleaseComObject(pFeatCur);
            return ids;
        }

        private List<int> GetNeedCheckIds(IFeatureLayer pFeatLyr, IGeometry pGeometry)
        {
            IFeatureClass pFeatCls = pFeatLyr.FeatureClass;
            List<int> ids = new List<int>();

            ISpatialFilter pSpatialFilter = new SpatialFilterClass();
            pSpatialFilter.GeometryField = pFeatCls.ShapeFieldName;
            pSpatialFilter.Geometry = pGeometry;
            pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;

            IFeatureCursor pFeatCur = pFeatLyr.Search(pSpatialFilter, false);
            IFeature pFeature;
            while ((pFeature = pFeatCur.NextFeature()) != null)
            {
                ids.Add(pFeature.OID);
            }

            pSpatialFilter = null;
            DataCheckUtility.ReleaseComObject(pFeatCur);
            return ids;
        }

        /// <summary>
        /// 获取要素图形中需要检查的点
        /// </summary>
        /// <param name="pFeature">要素</param>
        /// <param name="pGeometry">接边范围</param>
        /// <returns></returns>
        private IPointCollection GetNeedCheckPnts(IFeature pFeature, IGeometry pGeometry)
        {
            IPointCollection pPnts = new MultipointClass();
            
            ITopologicalOperator2 pTop = pGeometry as ITopologicalOperator2;
            pTop.IsKnownSimple_2 = false;
            pTop.Simplify();

            IRelationalOperator pRel = pGeometry as IRelationalOperator;
            IRelationalOperator pRel2 = pPnts as IRelationalOperator;

            if (pFeature.Shape.GeometryType == esriGeometryType.esriGeometryPolyline)
            {
                IGeometryCollection pGeometrys = pFeature.ShapeCopy as IGeometryCollection;

                IPoint pPntFrom, pPntTo;

                for (int i = 0; i < pGeometrys.GeometryCount; i++)
                {
                    IPointCollection pPolyline = pGeometrys.get_Geometry(i) as IPointCollection;
                    pPntFrom = pPolyline.get_Point (0);
                    if (pRel.Contains(pPntFrom) || pRel.Touches(pPntFrom)) 
                        if(!pRel2.Contains (pPntFrom))
                            pPnts.AddPoint(pPntFrom, ref Missing, ref Missing);

                    pPntTo = pPolyline.get_Point(pPolyline.PointCount - 1);
                    if (pRel.Contains(pPntTo) || pRel.Touches(pPntTo))
                        if (!pRel2.Contains(pPntTo))
                            pPnts.AddPoint(pPntTo, ref Missing, ref Missing);

                }
            }
            else if (pFeature.Shape.GeometryType == esriGeometryType.esriGeometryPolygon)
            {
                IPointCollection pPntsFeat = pFeature.ShapeCopy as IPointCollection;

                for (int i = 0; i < pPntsFeat.PointCount; i++)
                {
                    IPoint pPnt = pPntsFeat.get_Point(i);
                    if (pRel.Contains(pPnt) || pRel.Touches(pPnt))
                        if (!pRel2.Contains(pPnt))
                            pPnts.AddPoint(pPnt, ref Missing, ref Missing);
                }
            }

            return pPnts;
        }

        private Hashtable GetMergePointIdx(IPointCollection pPnts1, IPointCollection pPnts2)
        {
            Hashtable hashtable = new Hashtable();
            if (pPnts1.PointCount == 0 || pPnts2.PointCount == 0) return hashtable;
            for (int i = 0; i < pPnts1.PointCount; i++)
            {
                IPoint pPnt = pPnts1.get_Point(i);
                int idx = GetNearestPointIdx(pPnt, pPnts2);
                if (idx == -1) continue;
                
                //如果前面的点找到的最近点与该点找到的最近点是同一个点，则取距离最近的做检查
                if (hashtable.ContainsValue(idx))
                {
                    IPoint pPntIdx = pPnts2.get_Point(idx);
                    int previous = -1;
                    foreach (DictionaryEntry de in hashtable)
                    {
                        if ((int)de.Value == idx)
                        {
                            previous = (int)de.Key;
                            break;
                        }
                    }
                    IPoint pPntPrevious = pPnts1.get_Point(previous);

                    IProximityOperator pProx = pPntIdx as IProximityOperator;
                    //如果前面的点距离pPntIdx比该点小或等，则直接跳过；如果比该点大，则删除前面的记录，新增该点的记录
                    if (pProx.ReturnDistance(pPntPrevious) > pProx.ReturnDistance(pPnt))
                    {
                        hashtable.Remove(previous);
                        hashtable.Add(i, idx);
                    }
                }
                else
                {
                     hashtable.Add(i, idx);
                }
            }

            return hashtable;
        }

        private int GetNearestPointIdx(IPoint pPoint, IPointCollection pPnts)
        {
            int idx = -1;
            double disMin = -1;

            IRelationalOperator pRel = pPoint as IRelationalOperator;
            IProximityOperator pProx = pPoint as IProximityOperator;

            for (int i = 0; i < pPnts.PointCount; i++)
            {
                IPoint pPnt = pPnts.get_Point(i);
                if(pRel.Equals (pPnt))
                {
                    idx = i;
                    break;
                }

                double dis = pProx.ReturnDistance(pPnt);
                if (dis <= maxTol)
                {
                    if (disMin == -1 || dis <disMin)
                    {
                        disMin = dis;
                        idx = i;
                    }
                }
            }

            return idx;
        }

        /// <summary>
        /// 线层数据接边检查
        /// </summary>
        /// <param name="pFeatLyr"></param>
        /// <param name="pGeometry"></param>
        /// <returns></returns>
        private int PolylineMergeCheck(IFeatureLayer pFeatLyr, IGeometry pGeometry)
        {
            IFeatureClass pFeatCls =pFeatLyr.FeatureClass ;
            int errCount = 0;
            if (pFeatCls.ShapeType != esriGeometryType.esriGeometryPolyline)
            {
               LogHelper.WriteErrLog("["+pFeatCls.AliasName +"]不是线图层！");
                return 0;
            }

            List<int> ids = GetNeedCheckIds(pFeatLyr, pGeometry);
            if (ids == null || ids.Count == 0) return 0;

            setSubProcessBarMax.Invoke(ids.Count - 1);

            LogHelper.WriteLog("开始对[" + pFeatCls.AliasName + "]数据进行接边检查...");

            IRelationalOperator pRel = pGeometry as IRelationalOperator;

            IPoint pPntFrom, pPntTo;

            for (int i = 0; i < ids.Count-1; i++)
            {
                setSubProcessBarCurrent.Invoke(i + 1);
                if (IsStop()) break;

                IFeature pFeatCurrent = pFeatCls.GetFeature(ids[i]);

                #region 判断该要素是否需要做接边检查，并获取需要做检查的点的集合
                IGeometryCollection pGeosCurrent = pFeatCurrent.ShapeCopy as IGeometryCollection;
                IPointCollection pPntsCurrent = GetNeedCheckPnts(pFeatCurrent, pGeometry);

                //如果该要素所有部分的起始点都不再接边线缓冲范围内，则该要素无需做接边检查
                if (pPntsCurrent.PointCount == 0) continue;
                #endregion

                for (int j = i + 1; j < ids.Count; j++)
                {
                    IFeature pFeatNext = pFeatCls.GetFeature(ids[j]);

                    #region 排除不必要的检查
                    //如果两个要素的外包矩形之间的距离大于容限值上限，则无需检查
                    if (((IProximityOperator)pFeatCurrent.ShapeCopy.Envelope).ReturnDistance(pFeatNext.ShapeCopy.Envelope) > maxTol) continue;
                    //如果两个要素的图形之间的距离大于容限值上限，亦无须检查
                    if (((IProximityOperator)pFeatCurrent.ShapeCopy).ReturnDistance(pFeatNext.ShapeCopy) > maxTol) continue;
                    //如果两个要素的图形中心点连线穿过接边线，跳过检查
                    IPolyline pl1 = (IPolyline)pFeatCurrent.ShapeCopy;
                    IPolyline pl2 = (IPolyline)pFeatNext.ShapeCopy;
                    IPolyline pl = new PolylineClass();
                    IPoint from = new PointClass();
                    IPoint to = new PointClass();
                    pl1.QueryPoint(esriSegmentExtension.esriNoExtension, pl1.Length / 2, false, from);
                    pl2.QueryPoint(esriSegmentExtension.esriNoExtension, pl2.Length / 2, false, to);
                    pl.FromPoint = from;
                    pl.ToPoint = to;
                    pl.Project((pFeatCls as IGeoDataset).SpatialReference);
                    IRelationalOperator ro = pl as IRelationalOperator;
                    if (!ro.Crosses(pPolyline))
                        continue;
                    #endregion

                    #region 判断该要素是否需要做接边检查，并获取需要做检查的点的集合
                    IPointCollection pPntsNext = GetNeedCheckPnts(pFeatNext, pGeometry);
                    if (pPntsNext.PointCount == 0) continue;
                    #endregion

                    #region 获取需要进行检查的点的匹配关系
                    Hashtable hashtable = GetMergePointIdx(pPntsCurrent, pPntsNext);
                    if (hashtable.Count == 0) continue;
                    #endregion

                    #region 验证属性是否一致，并获取不一致的属性列表
                    bool isDifference = false;
                    List<string> differenceFields = GetNotSameValueFlds(pFeatCurrent, pFeatNext);
                    string dField = "";

                    bool isSameAttr;

                    if (differenceFields.Count == 0)
                    {
                        isSameAttr = true;
                    }
                    else
                    {
                        isSameAttr = false;
                        foreach (string differenceField in differenceFields)
                        {
                            dField = dField + "[" + differenceField + "]、";
                        }
                        dField = dField.Substring(0, dField.Length - 1);
                    }
                    #endregion

                    //记录在容限值下限之内的两点序号
                    Hashtable samepoints = new Hashtable();
                    //记录在容限值下限之外的两点序号
                    Hashtable differentpoints = new Hashtable();

                    #region old
                    //foreach (DictionaryEntry de in hashtable)
                    //{
                    //    IPoint pPntCurrent = pPntsCurrent.get_Point((int)de.Key);
                    //    IPoint pPntNext = pPntsNext.get_Point((int)de.Value);

                    //    double dis = (pPntCurrent as IProximityOperator).ReturnDistance(pPntNext);

                    //    if (isSameAttr)
                    //    {
                    //        //属性一致，两点又在容限值下限之内，属于未融合
                    //        if (dis <= minTol)
                    //        {
                    //            if (needSyncretizeCheck)
                    //            {
                    //                RecordListHelper.AddRecordItem("未融合", pFeatLyr, null, pFeatCurrent, pFeatNext, pPntCurrent, "");
                    //                //RecordListHelper.AddRecordItem("未融合", pFeatLyr, null, pFeatCurrent, pFeatNext, null, "");
                    //                errCount++;
                    //            }

                    //            //samepoints.Add(de.Key, de.Value);
                    //            //hashtable.Remove(de.Key);
                    //        }
                    //        else
                    //        {
                    //            differentpoints.Add(de.Key, de.Value);
                    //        }
                    //    }
                    //    else
                    //    {
                    //        //如果属性不一样，其中有两个点的距离又大于容限值下限，则无法判断这两个要素是否应该接边，故退出
                    //        if (dis > minTol)
                    //        {
                    //            isDifference = true;
                    //            differentpoints.Add(de.Key, de.Value);
                    //            break;
                    //        }
                    //        else
                    //        {
                    //            samepoints.Add(de.Key, de.Value);
                    //            //hashtable.Remove(de.Key);
                    //        }
                    //    }
                    //}

                    //if (isDifference) break;

                    ////differentpoints中为图形未接边
                    //foreach (DictionaryEntry de in differentpoints)
                    //{
                    //    IPoint pPntCurrent = pPntsCurrent.get_Point((int)de.Key);
                    //    IPoint pPntNext = pPntsNext.get_Point((int)de.Value);

                    //    #region 获取错误图形
                    //    IPolyline pErrPolyline = new PolylineClass();
                    //    pErrPolyline.FromPoint = pPntCurrent;
                    //    pErrPolyline.ToPoint = pPntNext;
                    //    pErrPolyline.Project((pFeatCls as IGeoDataset).SpatialReference);
                    //    #endregion

                    //    RecordListHelper.AddRecordItem("图形未接边", pFeatLyr, null, pFeatCurrent, pFeatNext, pErrPolyline, "");
                    //    //RecordListHelper.AddRecordItem("图形未接边", pFeatLyr, null, pFeatCurrent, pFeatNext, null, "");
                    //    errCount++;
                    //}

                    ////samepoints中为属性未接边
                    //foreach (DictionaryEntry de in samepoints)
                    //{
                    //    IPoint pPntCurrent = pPntsCurrent.get_Point((int)de.Key);
                    //    RecordListHelper.AddRecordItem("属性未接边", pFeatLyr, null, pFeatCurrent, pFeatNext, pPntCurrent, dField);
                    //    //RecordListHelper.AddRecordItem("属性未接边", pFeatLyr, null, pFeatCurrent, pFeatNext, null, dField);
                    //    errCount++;
                    //}
                    #endregion

                    foreach (DictionaryEntry de in hashtable)
                    {
                        IPoint pPntCurrent = pPntsCurrent.get_Point((int)de.Key);
                        IPoint pPntNext = pPntsNext.get_Point((int)de.Value);

                        double dis = (pPntCurrent as IProximityOperator).ReturnDistance(pPntNext);

                        if (isSameAttr)
                        {
                            //属性一致，两点又在容限值下限之内，属于未融合
                            if (dis <= minTol)
                            {
                                if (needSyncretizeCheck)
                                {
                                    RecordListHelper.AddRecordItem("未融合", pFeatLyr, null, pFeatCurrent, pFeatNext, null, "");
                                    errCount++;
                                    break;
                                }
                            }
                            else
                            {
                                RecordListHelper.AddRecordItem("图形未接边", pFeatLyr, null, pFeatCurrent, pFeatNext, null, "");
                                errCount++;
                                break;
                            }
                        }
                        else
                        {
                            //如果属性不一样，其中有两个点的距离又大于容限值下限，则无法判断这两个要素是否应该接边，故退出
                            if (dis > minTol)
                            {
                                isDifference = true;
                                break;
                            }
                            else
                            {
                                RecordListHelper.AddRecordItem("属性未接边", pFeatLyr, null, pFeatCurrent, pFeatNext, null, dField);
                                errCount++;
                                break;
                                //hashtable.Remove(de.Key);
                            }
                        }
                    }

                    if (isDifference) break;
                    
                    pPntsNext = null;
                    hashtable.Clear();
                    hashtable = null;
                    samepoints.Clear();
                    samepoints = null;
                    differentpoints.Clear();
                    differentpoints = null;
                }

                pPntsCurrent = null;
            }

            ids.Clear ();
            ids=null;

            LogHelper.WriteLog("[" + pFeatCls.AliasName + "]数据接边检查完毕，共发现" + errCount + "处错误。\r\n", zjgisLogType.zjgisLogDone);

            return errCount;
        }

        private int PolygonMergeCheck(IFeatureLayer pFeatLyr, IGeometry pGeometry)
        {
            IFeatureClass pFeatCls = pFeatLyr.FeatureClass;
            int errCount = 0;
            if (pFeatCls.ShapeType != esriGeometryType.esriGeometryPolygon)
            {
                LogHelper.WriteLog("[" + pFeatCls.AliasName + "]不是面图层！", zjgisLogType.zjgisLogError);
                return 0;
            }

            List<int> ids = GetNeedCheckIds(pFeatLyr, pGeometry);
            if (ids == null || ids.Count == 0) return 0;

            setSubProcessBarMax.Invoke(ids.Count - 1);

            LogHelper.WriteLog("开始对[" + pFeatCls.AliasName + "]数据进行接边检查...");

            IRelationalOperator pRel = pGeometry as IRelationalOperator;

            for (int i = 0; i < ids.Count - 1; i++)
            {
                setSubProcessBarCurrent.Invoke(i + 1);
                if (IsStop()) break;

                IFeature pFeatCurrent = pFeatCls.GetFeature(ids[i]);

                #region 判断该要素是否需要做接边检查，并获取需要做检查的点的集合
                IGeometryCollection pGeosCurrent = pFeatCurrent.ShapeCopy as IGeometryCollection;
                IPointCollection pPntsCurrent = GetNeedCheckPnts(pFeatCurrent, pGeometry);

                //如果该要素的节点少于两个落入到接边线缓冲范围之内，则该要素无需检查
                if (pPntsCurrent.PointCount < 2) continue;
                #endregion

                for (int j = i + 1; j < ids.Count; j++)
                {
                    IFeature pFeatNext = pFeatCls.GetFeature(ids[j]);    
                    #region 排除不必要的检查
                    //如果两个要素的外包矩形之间的距离大于容限值上限，则无需检查
                    if (((IProximityOperator)pFeatCurrent.ShapeCopy.Envelope).ReturnDistance(pFeatNext.ShapeCopy.Envelope) > maxTol) continue;
                    //如果两个要素的图形之间的距离大于容限值上限，亦无须检查
                    if (((IProximityOperator)pFeatCurrent.ShapeCopy).ReturnDistance(pFeatNext.ShapeCopy) > maxTol) continue;
                    //如果两个要素的图形中心点连线穿过接边线，跳过检查
                    IPolyline pl = new PolylineClass();
                    pl.FromPoint = ((IArea)pFeatCurrent.ShapeCopy).Centroid;
                    pl.ToPoint = ((IArea)pFeatNext.ShapeCopy).Centroid;
                    pl.Project((pFeatCls as IGeoDataset).SpatialReference);
                    IRelationalOperator ro = pl as IRelationalOperator;
                    if (!ro.Crosses(pPolyline))
                        continue;
                    #endregion

                    #region 判断该要素是否需要做接边检查，并获取需要做检查的点的集合
                    IPointCollection pPntsNext = GetNeedCheckPnts(pFeatNext, pGeometry);
                    if (pPntsNext.PointCount < 2) continue;
                    #endregion


                    #region 获取需要进行检查的点的匹配关系
                    Hashtable hashtable = GetMergePointIdx(pPntsCurrent, pPntsNext);
                    if (hashtable.Count < 2) continue;
                    #endregion

                    #region 验证属性是否一致，并获取不一致的属性列表
                    bool isDifference = false;
                    List<string> differenceFields = GetNotSameValueFlds(pFeatCurrent, pFeatNext);
                    string dField = "";

                    bool isSameAttr;

                    if (differenceFields.Count == 0)
                    {
                        isSameAttr = true;
                    }
                    else
                    {
                        isSameAttr = false;
                        foreach (string differenceField in differenceFields)
                        {
                            dField = dField + "[" + differenceField + "]、";
                        }
                        dField = dField.Substring(0, dField.Length - 1);
                    }
                    #endregion

                    bool bAddRec = false;

                    foreach (DictionaryEntry de in hashtable)
                    {
                        IPoint pPntCurrent = pPntsCurrent.get_Point((int)de.Key);
                        IPoint pPntNext = pPntsNext.get_Point((int)de.Value);

                        double dis = (pPntCurrent as IProximityOperator).ReturnDistance(pPntNext);

                        if (dis > minTol)
                        {
                            //RecordListHelper.AddRecordItem("图形未接边", pFeatLyr, null, pFeatCurrent, pFeatNext, pErrPolyline, "");
                            RecordListHelper.AddRecordItem("图形未接边", pFeatLyr, null, pFeatCurrent, pFeatNext, null, "");
                            bAddRec = true;
                            errCount++;
                            break;
                        }
                    }

                    if (isSameAttr)
                    {
                        if (needSyncretizeCheck)
                        {
                            //RecordListHelper.AddRecordItem("未融合", pFeatLyr, null, pFeatCurrent, pFeatNext, pPntCurrent, "");
                            RecordListHelper.AddRecordItem("未融合", pFeatLyr, null, pFeatCurrent, pFeatNext, null, "");
                            errCount++;
                        }
                    }
                    else
                    {
                        //RecordListHelper.AddRecordItem("属性未接边", pFeatLyr, null, pFeatCurrent, pFeatNext, pPntCurrent, dField);
                        RecordListHelper.AddRecordItem("属性未接边", pFeatLyr, null, pFeatCurrent, pFeatNext, null, dField);
                        errCount++;
                    }



                    //foreach (DictionaryEntry de in hashtable)
                    //{
                    //    IPoint pPntCurrent = pPntsCurrent.get_Point((int)de.Key);
                    //    IPoint pPntNext = pPntsNext.get_Point((int)de.Value);

                    //    #region 获取错误图形
                    //    IPolyline pErrPolyline = new PolylineClass();
                    //    pErrPolyline.FromPoint = pPntCurrent;
                    //    pErrPolyline.ToPoint = pPntNext;
                    //    pErrPolyline.Project((pFeatCls as IGeoDataset).SpatialReference);
                    //    #endregion

                    //    double dis = (pPntCurrent as IProximityOperator).ReturnDistance(pPntNext);

                    //    if (dis>minTol)
                    //    {
                    //        //RecordListHelper.AddRecordItem("图形未接边", pFeatLyr, null, pFeatCurrent, pFeatNext, pErrPolyline, "");
                    //        RecordListHelper.AddRecordItem("图形未接边", pFeatLyr, null, pFeatCurrent, pFeatNext, null, "");
                    //        errCount++;
                    //    }
                    //    else 
                    //    {
                    //        if(isSameAttr )
                    //        {
                    //            if(needSyncretizeCheck)
                    //            {
                    //                //RecordListHelper.AddRecordItem("未融合", pFeatLyr, null, pFeatCurrent, pFeatNext, pPntCurrent, "");
                    //                RecordListHelper.AddRecordItem("未融合", pFeatLyr, null, pFeatCurrent, pFeatNext, null, "");
                    //                errCount++;
                    //            }
                    //        }
                    //        else 
                    //            {
                    //                //RecordListHelper.AddRecordItem("属性未接边", pFeatLyr, null, pFeatCurrent, pFeatNext, pPntCurrent, dField);
                    //                RecordListHelper.AddRecordItem("属性未接边", pFeatLyr, null, pFeatCurrent, pFeatNext, null, dField);
                    //            errCount++;
                    //        }
                    //    }
                    //}

                    pPntsNext = null;
                    hashtable.Clear();
                    hashtable = null;
                }
                pPntsCurrent = null;
            }
            ids.Clear();
            ids = null;

            LogHelper.WriteDoneLog("[" + pFeatCls.AliasName + "]数据接边检查完毕，共发现" + errCount + "处错误。\r\n");

            return errCount;
        }
    }
}
